package cn.t.redis.limiter.aspect;

import cn.t.redis.limiter.annotations.RateLimit;
import cn.t.redis.limiter.components.RateLimiter;
import cn.t.redis.limiter.exception.RateLimitException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;

/**
 * 限流器切面类
 */
@Aspect
public class RateLimitAspect {

    private static final Logger logger = LoggerFactory.getLogger(RateLimitAspect.class);

    private RateLimiter rateLimiter;

    public RateLimitAspect(RateLimiter rateLimiter) {
        this.rateLimiter = rateLimiter;
    }

    /**
     * 标注切点-所有标识了RateLimit注解的方法
     */
    @Pointcut("@annotation(cn.t.redis.limiter.annotations.RateLimit)")
    public void pointCut(){};

    @Before("pointCut()")
    public void before(JoinPoint joinPoint) {
        Method method = ((MethodSignature)joinPoint.getSignature()).getMethod();
        RateLimit a = method.getAnnotation(RateLimit.class);
        if (a != null) {
            String name = a.interfaceName();
            long maxPermits = a.maxPermits();
            long tokensPerSeconds = a.tokensPerSeconds();
            // 执行限流判断
            var ret = this.rateLimiter.tryAcquire(name, maxPermits, tokensPerSeconds);
            if (!ret) {
                throw new RateLimitException("the interface can not be accessed in the meantime...");
            }
        }
    }
}
